home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 2000 August: Tool Chest / Dev.CD Aug 00 TC Disk 2.toast / pc / sample code / quicktime / goodies / qtstdcompr / qtstdcompr.c < prev    next >
Encoding:
Text File  |  2000-06-23  |  12.0 KB  |  385 lines

  1. //////////
  2. //
  3. //    File:        QTStdCompr.c
  4. //
  5. //    Contains:    Sample code for using QuickTime's standard image compression dialog routines.
  6. //
  7. //    Written by:    Tim Monroe
  8. //                Based on existing code by Apple Developer Technical Support, which was itself
  9. //                based on the code in Chapter 3 of Inside Macintosh: QuickTime Components.
  10. //
  11. //    Copyright:    © 1998 by Apple Computer, Inc., all rights reserved.
  12. //
  13. //    Change History (most recent first):
  14. //
  15. //       <4>         02/03/99    rtm        reworked prompt and filename handling to remove "\p" sequences
  16. //       <3>         04/23/98    rtm        added extended procedures support; everything seems to work
  17. //                                    fine on both Mac and Windows
  18. //       <2>         04/22/98    rtm        revised to personal coding style and made cross-platform
  19. //       <1>         12/04/94    khs        first file
  20. //       
  21. //    This sample code illustrates how to use QuickTime's standard image compression dialog routines
  22. //    to get compression settings from the user and to compress an image using those settings. See
  23. //    Chapter 3 of Inside Macintosh: QuickTime Components for complete information on the standard
  24. //    image compression dialog routines.
  25. //
  26. //    In this sample, we prompt the user to open an image file; then we display the standard image
  27. //    compression dialog box and use the settings selected by the user to compress the image. The 
  28. //    Standard Image Compression Dialog Component currently supports three sources for the image:
  29. //
  30. //        (1) a PICT handle
  31. //        (2) a PICT file
  32. //        (3) a pixel map
  33. //
  34. //    The most general of these is the pixel map, so we'll use that throughout this sample. We can
  35. //    create a pixel map by opening an image file and drawing it into an offscreen graphics world.
  36. //    By using the graphics importer routines, we allow ourselves to handle ANY kind of image file for
  37. //    which QuickTime supplies a graphics importer component. So, for free, we get support for PICT
  38. //    files too.
  39. //
  40. //    This sample also shows how to extend the basic user interface by installing a modal-dialog filter
  41. //    function and a hook function to handle the optional custom button in the dialog box. If you don't
  42. //    want this extended behavior, set gUseExtendedProcs to false.
  43. //
  44. //    NOTES:
  45. //
  46. //    *** (1) ***
  47. //    Using the SCCompressImage function to compress a pixmap using some of the available compression
  48. //    types (for instance, BMP) results in a block of compressed data that does not contain the required
  49. //    headers. As a result, saving that data into a file results in an invalid image file. This is a
  50. //    known limitation of QuickTime 3 and may be fixed in the future. Currently the only way to generate
  51. //    these headers is to use a graphics importer to export the file as a BMP (or whatever) file. This
  52. //    is NOT illustrated in this sample code.
  53. //    
  54. //    *** (2) ***
  55. //    You can use the SCSetInfo function with the scSettingsStateType selector to retrieve a handle
  56. //    containing the current compression settings; this might be useful if you were allowing the user
  57. //    to compress a series of images and wanted to preserve the user's settings from one image to the
  58. //    next (instead of reverting to the defaults for every image). Note, however, that the data in
  59. //    that handle is byte-ordered according to the platform the code is running on. As a result, you
  60. //    should not store that data in a file and expect that file to be valid on other platforms. To
  61. //    get a handle of data in a platform-independent format, use the function SCGetSettingsAsAtomContainer
  62. //    (introduced in QuickTime 3); to restore the settings in that handle, use the related function
  63. //    SCSetSettingsAsAtomContainer.
  64. //    
  65. //////////
  66.  
  67. //////////
  68. //
  69. // header files
  70. //       
  71. //////////
  72.  
  73. #include "QTStdCompr.h"
  74.  
  75. //////////
  76. //
  77. // global variables
  78. //       
  79. //////////
  80.  
  81. Boolean                            gUseExtendedProcs = true;    // do we use extended procs with our dialog box?
  82. SCExtendedProcs                 gProcStruct;
  83.  
  84. // our application's window-updating function
  85. extern void DoUpdateWindow (WindowRef theWindow, Rect *theRefreshArea);
  86.  
  87. //////////
  88. //
  89. // QTStdCompr_PromptUserForImageFileAndCompress
  90. // Let the user select an image file and select its compression settings; then compress it.
  91. //
  92. //////////
  93.  
  94. void QTStdCompr_PromptUserForImageFileAndCompress (void)
  95. {
  96.     SFTypeList                    myTypeList;
  97.     StandardFileReply            myReply;
  98.     Rect                        myRect;
  99.     GraphicsImportComponent        myImporter = NULL;
  100.     ComponentInstance            myComponent = NULL;
  101.     GWorldPtr                    myImageWorld = NULL;        // the graphics world we draw the image in
  102.     PixMapHandle                myPixMap = NULL;
  103.     ImageDescriptionHandle        myDesc = NULL;
  104.     Handle                        myHandle = NULL;
  105.     OSErr                        myErr = noErr;
  106.  
  107.     //////////
  108.     //
  109.     // have the user select an image file
  110.     //
  111.     //////////
  112.  
  113.     // kQTFileTypeQuickTimeImage means any image file readable by GetGraphicsImporterForFile
  114.     myTypeList[0] = kQTFileTypeQuickTimeImage;
  115.  
  116.     StandardGetFilePreview(NULL, 1, myTypeList, &myReply);
  117.     if (!myReply.sfGood)
  118.         goto bail;
  119.     
  120.     //////////
  121.     //
  122.     // get a graphics importer for the image file and determine the natural size of the image
  123.     //
  124.     //////////
  125.  
  126.     myErr = GetGraphicsImporterForFile(&myReply.sfFile, &myImporter);
  127.     if (myErr != noErr)
  128.         goto bail;
  129.     
  130.     myErr = GraphicsImportGetNaturalBounds(myImporter, &myRect);
  131.     if (myErr != noErr)
  132.         goto bail;
  133.         
  134.     //////////
  135.     //
  136.     // create an offscreen graphics world and draw the image into it
  137.     //
  138.     //////////
  139.     
  140.     myErr = NewGWorld(&myImageWorld, 0, &myRect, NULL, NULL, 0L);
  141.     if (myErr != noErr)
  142.         goto bail;
  143.     
  144.     // get the pixmap of the GWorld; we'll lock the pixmap, just to be safe
  145.     myPixMap = GetGWorldPixMap(myImageWorld);
  146.     if (!LockPixels(myPixMap))
  147.         goto bail;
  148.     
  149.     // set the current port and draw the image
  150.     GraphicsImportSetGWorld(myImporter, (CGrafPtr)myImageWorld, NULL);
  151.     GraphicsImportDraw(myImporter);
  152.     
  153.     //////////
  154.     //
  155.     // display the standard image compression dialog box
  156.     //
  157.     //////////
  158.     
  159.     // open the standard compression dialog component
  160.     myComponent = OpenDefaultComponent(StandardCompressionType, StandardCompressionSubType);
  161.     if (myComponent == NULL)
  162.         goto bail;
  163.         
  164.     // set the picture to be displayed in the dialog box; passing NULL for the rect
  165.     // means use the entire image; passing 0 for the flags means to use the default
  166.     // system method of displaying the test image, which is currently a combination
  167.     // of cropping and scaling; personally, I prefer scaling (your milage may vary)
  168.     SCSetTestImagePixMap(myComponent, myPixMap, NULL, scPreferScaling);
  169.  
  170.     // install the custom procs, if requested
  171.     // we can install two kinds of custom procedures for use in connection with
  172.     // the standard dialog box: (1) a modal-dialog filter function, and (2) a hook
  173.     // function to handle the custom button in the dialog box
  174.     if (gUseExtendedProcs)
  175.         QTStdCompr_InstallExtendedProcs(myComponent, (long)myPixMap);
  176.     
  177.     // request image compression settings from the user; in other words, put up the dialog box
  178.     myErr = SCRequestImageSettings(myComponent);
  179.     if (myErr == scUserCancelled)
  180.         goto bail;
  181.  
  182.     //////////
  183.     //
  184.     // compress the image
  185.     //
  186.     //////////
  187.     
  188.     myErr = SCCompressImage(myComponent, myPixMap, NULL, &myDesc, &myHandle);
  189.     if (myErr != noErr)
  190.         goto bail;
  191.  
  192.     //////////
  193.     //
  194.     // save the compressed image in a new file
  195.     //
  196.     //////////
  197.     
  198.     QTStdCompr_PromptUserForDiskFileAndSaveCompressed(myHandle, myDesc);
  199.     
  200. bail:
  201.     if (gUseExtendedProcs)
  202.         QTStdCompr_RemoveExtendedProcs();
  203.  
  204.     if (myPixMap != NULL)
  205.         if (GetPixelsState(myPixMap) & pixelsLocked)
  206.             UnlockPixels(myPixMap);
  207.     
  208.     if (myImporter != NULL)
  209.         CloseComponent(myImporter);
  210.             
  211.     if (myComponent != NULL)
  212.         CloseComponent(myComponent);
  213.  
  214.     if (myDesc != NULL)
  215.         DisposeHandle((Handle)myDesc);
  216.  
  217.     if (myHandle != NULL)
  218.         DisposeHandle(myHandle);
  219.  
  220.     if (myImageWorld != NULL)
  221.         DisposeGWorld(myImageWorld);
  222. }
  223.  
  224.  
  225. //////////
  226. //
  227. // QTStdCompr_PromptUserForDiskFileAndSaveCompressed
  228. // Let the user select a disk file, then write the compressed image into that file.
  229. //
  230. //////////
  231.  
  232. void QTStdCompr_PromptUserForDiskFileAndSaveCompressed (Handle theHandle, ImageDescriptionHandle theDesc)
  233. {
  234.     StandardFileReply            myReply;
  235.     short                        myRefNum = -1;
  236.     StringPtr                     myMoviePrompt = QTUtils_ConvertCToPascalString(kSaveMoviePrompt);
  237.     StringPtr                     myMovieFileName = QTUtils_ConvertCToPascalString(kSaveMovieFileName);
  238.     OSErr                        myErr = noErr;
  239.  
  240.     // do a little sanity-checking....
  241.     if ((theHandle == NULL) || (theDesc == NULL))
  242.         goto bail;
  243.         
  244.     if ((**theDesc).dataSize > GetHandleSize(theHandle))
  245.         goto bail;
  246.  
  247.     // prompt the user for a file to put the compressed image into; in theory, the name
  248.     // should have a file extension appropriate to the type of compressed data selected by the user;
  249.     // this is left as an exercise for the reader
  250.     StandardPutFile(myMoviePrompt, myMovieFileName, &myReply);
  251.     if (!myReply.sfGood)
  252.         goto bail;
  253.     
  254.     HLock(theHandle);
  255.  
  256.     // create and open the file
  257.     myErr = FSpCreate(&myReply.sfFile, kImageFileCreator, (**theDesc).cType, 0);
  258.     
  259.     if (myErr == noErr)
  260.         myErr = FSpOpenDF(&myReply.sfFile, fsRdWrPerm, &myRefNum);
  261.         
  262.     if (myErr == noErr)
  263.         myErr = SetFPos(myRefNum, fsFromStart, 0);
  264.  
  265.     // now write the data in theHandle into the file
  266.     if (myErr == noErr)
  267.         myErr = FSWrite(myRefNum, &(**theDesc).dataSize, *theHandle);
  268.     
  269.     if (myErr == noErr)
  270.         myErr = SetFPos(myRefNum, fsFromStart, (**theDesc).dataSize);
  271.  
  272.     if (myErr == noErr)
  273.         myErr = SetEOF(myRefNum, (**theDesc).dataSize);
  274.                  
  275.     if (myRefNum != -1)
  276.         myErr = FSClose(myRefNum);
  277.         
  278. bail:
  279.     free(myMoviePrompt);
  280.     free(myMovieFileName);
  281.  
  282.     HUnlock(theHandle);
  283. }
  284.  
  285.  
  286. //////////
  287. //
  288. // QTStdCompr_InstallExtendedProcs
  289. // Install the modal-dialog filter function and the hook function.
  290. //
  291. //////////
  292.  
  293. void QTStdCompr_InstallExtendedProcs (ComponentInstance theComponent, long theRefCon)
  294. {
  295.     StringPtr         myButtonTitle = QTUtils_ConvertCToPascalString(kButtonTitle);
  296.  
  297.     // the modal-dialog filter function can be used to handle any events that
  298.     // the standard image compression dialog handler doesn't know about, such
  299.     // as any update events for windows owned by the application
  300.     gProcStruct.filterProc = NewSCModalFilterProc(QTStdCompr_FilterProc);
  301.     
  302.     // the hook function can be used to handle clicks on the custom button
  303.     gProcStruct.hookProc = NewSCModalHookProc(QTStdCompr_ButtonProc);
  304.  
  305.     // in this example, we pass the pixel map handle as a refcon
  306.     gProcStruct.refcon = theRefCon;
  307.     
  308.     // copy the string for our custom button into the extended procs structure
  309.     BlockMove(myButtonTitle, gProcStruct.customName, 9);
  310.  
  311.     // set the current extended procs
  312.     SCSetInfo(theComponent, scExtendedProcsType, &gProcStruct);
  313.     
  314.     free(myButtonTitle);
  315. }
  316.  
  317.  
  318. //////////
  319. //
  320. // QTStdCompr_RemoveExtendedProcs
  321. // Remove the modal-dialog filter function and the hook function.
  322. //
  323. //////////
  324.  
  325. void QTStdCompr_RemoveExtendedProcs (void)
  326. {
  327.     // clear out the extended procedures
  328.     SCSetInfo((ComponentInstance)gProcStruct.refcon, scExtendedProcsType, NULL);
  329.     
  330.     // dispose of routine descriptors
  331.     DisposeRoutineDescriptor(gProcStruct.filterProc);
  332.     DisposeRoutineDescriptor(gProcStruct.hookProc);
  333. }
  334.  
  335.  
  336. //////////
  337. //
  338. // QTStdCompr_FilterProc
  339. // Filter events for a standard modal dialog box. 
  340. //
  341. //////////
  342.  
  343. PASCAL_RTN Boolean QTStdCompr_FilterProc (DialogPtr theDialog, EventRecord *theEvent, short *theItemHit, long theRefCon)
  344. {
  345. #pragma unused(theDialog, theItemHit, theRefCon)
  346.     Boolean            myEventHandled = false;
  347.     WindowRef        myWindow = NULL;
  348.         
  349.     switch (theEvent->what) {
  350.         case updateEvt:
  351.             // update the specified window, if it's behind the modal dialog
  352.             myWindow = (WindowRef)theEvent->message;
  353.             if ((myWindow != NULL) && (myWindow != theDialog)) {
  354.                 DoUpdateWindow(myWindow, &(**(myWindow->visRgn)).rgnBBox);
  355.                 myEventHandled = false;        // so sayeth IM
  356.             }
  357.             break;
  358.     }
  359.     
  360.     return(myEventHandled);
  361. }
  362.  
  363.  
  364. //////////
  365. //
  366. // QTStdCompr_ButtonProc
  367. // Handle item selections in the standard image compression dialog box.
  368. //
  369. // The theParams parameter is the component instance of the standard image compression
  370. // dialog component. Also, the theRefCon paramter is handle to our pixel map.
  371. //
  372. //////////
  373.  
  374. PASCAL_RTN short QTStdCompr_ButtonProc (DialogPtr theDialog, short theItemHit, void *theParams, long theRefCon)
  375. {
  376. #pragma unused(theDialog)
  377.     // in this sample code, we'll have the settings revert to their default values
  378.     // when the user clicks on the custom button
  379.     if (theItemHit == scCustomItem)
  380.         SCDefaultPixMapSettings(theParams, (PixMapHandle)theRefCon, false);
  381.  
  382.     // always return the item passed in
  383.     return(theItemHit);
  384. }
  385.